/**
 * 
 */
package photosalvage.rs.users;

import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.EmailValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import photosalvage.PhotoSalvageConstants;
import photosalvage.entity.User;
import photosalvage.entity.UserDto;
import photosalvage.entity.UserRepository;
import photosalvage.rs.AuthNotRequired;
import photosalvage.rs.BaseResource;
import photosalvage.rs.WebUtils;

import com.google.common.collect.ImmutableMap;
import com.sun.jersey.api.NotFoundException;
import com.sun.jersey.api.view.Viewable;

/**
 * @author shumpei
 *
 */
@Path("/users")
public class Users extends BaseResource {
	private static final Logger logger = LoggerFactory.getLogger(Users.class);
	
	@Inject
	private UserRepository userRepository;
	
	/**
	 * 管理用の隠しコマンド。
	 * ユーザID0番のユーザを作成する。
	 * メールアドレスは「admin@photosalvage.net」パスワードは「__admin123」となる。
	 * @return
	 */
	@Path("/__initAdministrator__")
	@GET
	@AuthNotRequired
	@Produces("text/plain")
	public String initAdministrator() {
		User admin = userRepository.find(0L);
		if (admin == null) {
			userRepository.create(new UserDto("admin@photosalvage.net", "管理者", "__admin123", true));
		}
		return "OK";
	}
	
	@Path("/login.html")
	@GET
	@AuthNotRequired
	public Response loginPage() {
		@SuppressWarnings("unchecked")
		Map<String, Object> context = (Map<String, Object>) request.getAttribute("context");
		return Response.ok(new Viewable("/pc/users/login.jsp", context)).build();
	}
	
	/**
	 * 
	 * @return
	 */
	@Path("/login")
	@POST
	@AuthNotRequired
	public Response login(@FormParam("email") String email,
			@FormParam("password") String password) {
		User user = userRepository.findByCredentials(email, password);
		if (user == null) {
			saveErrors("ユーザ名、またはパスワードに誤りがあります。");
			return loginPage();
		}
		request.getSession(true).setAttribute(PhotoSalvageConstants.SESSION_KEY_USER, user);
		logger.info("ユーザ[ID:[{}],Email:[{}]がログインしました。", user.getId(), email);
		return WebUtils.redirect2TopPage();
	}
	
	/**
	 * 
	 * @return
	 */
	@GET
	@Path("/logout")
	public Response logout() {
		HttpSession session = request.getSession(false);
		if (session != null) {
			session.invalidate();
		}
		return WebUtils.redirect2TopPage();
	}
	
	@Path("/create.html")
	@GET
	public Response createPage() {
		@SuppressWarnings("unchecked")
		Map<String, Object> context = (Map<String, Object>) request.getAttribute("context");
		return Response.ok(new Viewable("/pc/users/create.jsp", context)).build();
	}
	
	/**
	 * 
	 * @return
	 */
	@POST
	public Response create(
			@FormParam("email") String email,
			@FormParam("name") String name,
			@FormParam("password") String password,
			@FormParam("admin") boolean admin) {
		UserDto param = new UserDto(email, name, password, admin);
		
		if (userRepository.findByEmail(email) != null) {
			saveErrors("このメールアドレスは既に登録されています。");
		} else {
			if (StringUtils.isEmpty(email)) {
				saveErrors("メールアドレスを入力してください。");
			} else if (!EmailValidator.getInstance().isValid(email)) {
				saveErrors("メールアドレスが不正です。");
			}
		}
		if (StringUtils.isEmpty(name)) {
			saveErrors("名前を入力してください。");
		}
		if (StringUtils.isEmpty(password)) {
			saveErrors("パスワードを入力してください。");
		}
		Map<String, UserDto> context = ImmutableMap.of("user", param);
		request.setAttribute("context", context);
		if (!hasErrors()) {
				userRepository.create(param);
				saveInformations("ユーザ作成に成功しました。");
		}
		return createPage();
	}
	
	@Path("/update.html")
	@GET
	public Response updatePage(@PathParam("id") Long userId) {
		@SuppressWarnings("unchecked")
		Map<String, Object> context = (Map<String, Object>) request.getAttribute("context");
		if (context == null) {
			context = new HashMap<String, Object>();
		} else {
			context = new HashMap<String, Object>(context);
		}
		User user = getCurrentUser();
		// 自分以外のユーザを変更できるのは管理人のみ
		if (userId != null && !user.getId().equals(userId)) {
			if (!user.isAdministrator()) {
				throw new WebApplicationException(Response.Status.FORBIDDEN);
			}
			user = userRepository.find(userId);
			if (user == null) {
				throw new NotFoundException("更新対象のユーザが見つかりません。");
			}
		}
		context.put("user", user);
		return Response.ok(new Viewable("/pc/users/update.jsp", context)).build();
	}
	
	@Path("/{id: \\d+}")
	@POST
	@Produces("text/html")
	public Response update(
			@PathParam("id") Long userId,
			@FormParam("name") String name,
			@FormParam("password") String password) {
		User user = userRepository.find(userId);
		if (user == null) {
			throw new NotFoundException();
		}
		if (StringUtils.isEmpty(name)) {
			saveErrors("名前を入力してください。");
		}
		// パスワードが入力されなかった場合は、パスワードを変更する意志がないということ
		if (StringUtils.isEmpty(password)) {
		//	saveErrors("パスワードを入力してください。");
			password = null;
		}
		UserDto param = new UserDto(user.getEmail(), name, password, user.isAdministrator(), userId);
		if (!hasErrors()) {
			userRepository.update(param);
			saveInformations("ユーザ更新に成功しました。");
		}
		Map<String, UserDto> context = ImmutableMap.of("user", param);
		request.setAttribute("context", context);
		return updatePage(userId);
	}
}
